unit smMain;

interface

uses
  SysUtils, Windows, smExceptions, smConst, Gen2, Direct3D9;

type
  TGameApplication = class(TG2App)
  protected
    FFontSystem: TG2Font;
    FInputPlugin: TG2PlugInput;

    procedure OnUpdate(); override;
    procedure OnRender(); override;
    procedure OnMouseMove(const Shift: TPoint); override;
    procedure OnMouseDown(const Button: Byte); override;
    procedure OnMouseUp(const Button: Byte); override;
    procedure OnKeyPress(const Key: AnsiChar); override;

  public
    property InputPlugin: TG2PlugInput read FInputPlugin;
    property FontSystem: TG2Font read FFontSystem;

    procedure Initialize(); override;
    procedure BeforeFinalize();

  end;

var
  Game: TGameApplication;
  Engine: TG2Core;

implementation

uses
  smGUI, smSceneManager, smCommonTypes, smLuaUtils, smPlayer, smWorld;

{ TGameApplication }

procedure TGameApplication.Initialize;
begin
  with Gfx.InitParams do
  begin
    Width  := ScreenWidth;
    Height := ScreenHeight;
    FullScreen := False;
    FormatBackBuffer := D3DFMT_A8R8G8B8;
    FormatSurfaceRT  := D3DFMT_A8R8G8B8;
    FormatSurfaceDS  := D3DFMT_D24S8;
    FormatTexture2D  := D3DFMT_A8R8G8B8;
  end;
  g2.Handle := WindowCreate(ScreenWidth, ScreenHeight, 'The Sentinels');

  with Tmr do
  begin
    Mode   := tmManual;
    MaxFPS := 60;
  end;

  inherited Initialize();
  if not g2.Initialized then
    raise EEngineInitialize.Create('error initializing g2')
  else
    Engine := g2; // shortcut

  // Start scripting system
  if not InitScripting() then
    raise EEngineInitialize.Create('error starting scripting');

  // Resources
  g2.RequestPlug(TG2PlugInput, @FInputPlugin);
  FFontSystem := Gfx.Shared.RequestFont('Courier New', 10);

  GUIManager := TGUI.Create();
  GUIManager.Initialize('layout');

  Player := TPlayer.Create(); // it also creates world

  SceneManager := TSceneManager.Create();
  SceneManager.AddScene('main_menu', stMenu);
  SceneManager.AddScene('level', stLevel);
  SceneManager.SetNextScene('main_menu');

  // Let's rock!
  Tmr.Enabled := True;
end;

procedure TGameApplication.OnMouseMove(const Shift: TPoint);
begin
  if SceneManager.CurrentScene.State = ssReady then
    if SceneManager.CurrentScene.SystemType <> stLevel then
      GUIManager.Dispatch(
        gmMouseMove, InputPlugin.MousePos.X, InputPlugin.MousePos.Y
      )

    else
      if not GUIManager.Dispatch(
          gmMouseMove, InputPlugin.MousePos.X, InputPlugin.MousePos.Y
        ) and (Player.World.State = wsReady) then
        // Player.World.Dispatch ()
end;

procedure TGameApplication.OnMouseUp(const Button: Byte);
begin
  if SceneManager.CurrentScene.State = ssReady then
    if SceneManager.CurrentScene.SystemType <> stLevel then
      GUIManager.Dispatch(gmMouseUp, Button, 0)
    else
      if not GUIManager.Dispatch(gmMouseUp, Button, 0)
        and (Player.World.State = wsReady) then
        // Player.World.Dispatch ()
end;

procedure TGameApplication.OnMouseDown(const Button: Byte);
begin
  if SceneManager.CurrentScene.State = ssReady then
    if SceneManager.CurrentScene.SystemType <> stLevel then
      GUIManager.Dispatch(gmMouseDown, Button, 0)
    else
      if not GUIManager.Dispatch(gmMouseDown, Button, 0)
        and (Player.World.State = wsReady) then
        // Player.World.Dispatch ()
end;

procedure TGameApplication.OnKeyPress(const Key: AnsiChar);
begin
  if SceneManager.CurrentScene.State = ssReady then
    if SceneManager.CurrentScene.SystemType <> stLevel then
      GUIManager.Dispatch(gmKeyPress, Ord(Key), 0)
    else
      if not GUIManager.Dispatch(gmKeyPress, Ord(Key), 0)
        and (Player.World.State = wsReady) then
        // Player.World.Dispatch ()
end;

procedure TGameApplication.OnRender;
begin
  if Render.CanRender then
  begin
    Render.Clear(True, True, True, $C0C0C0);
    Render.RenderStart();

      SceneManager.Render();

      RenderModes.FilteringLinear();
      FontSystem.Print(
        10, 10, $FF8080F0, AnsiString(Format('FPS: %d', [Tmr.FPS]))
      );
    Render.RenderStop();
    Render.Present();
  end;
end;

procedure TGameApplication.OnUpdate;
begin
  if Render.CanRender then
  begin
    SceneManager.Update();
  end;
end;

procedure TGameApplication.BeforeFinalize;
begin
  SceneManager.Free();
  Player.Free(); // it also frees world
  GUIManager.Free();

  UninitScripting();

  Engine := nil;
  g2.ReleasePlug(@FInputPlugin);
end;

end.
